<template>
<div>
  <a-dropdown :trigger="['click']" v-model="show" :overlayStyle="{ width: '297px', top: '50px' }">
    <div slot="overlay">
      <a-spin :spinning="loading">
        <a-card>
          <a-list class="tab-pane">
            <template v-if="dataSource.length">
              <template v-for="(item,i) in dataSource">
                <a-list-item :key="i" @click="handleDetail(item)" style="cursor: pointer;">
                  <a-list-item-meta :title="item.messageTitle" :description="item.createTime">
                    <a-avatar style="background-color: #79919d" slot="avatar" icon="message" />
                  </a-list-item-meta>
                </a-list-item>
              </template>
            </template>
            <a-empty description="无新消息" v-else />
            <div style="margin-top: 5px;text-align: center">
              <a-button @click="toMyAnnouncement()" type="dashed" block>查看更多</a-button>
            </div>
          </a-list>
        </a-card>
        <!-- <a-tabs class="dropdown-tabs" :tabBarStyle="{textAlign: 'center'}" :style="{width: '297px'}">
          <a-tab-pane tab="站内信" key="1">

          </a-tab-pane>
          <a-tab-pane tab="消息" key="2">
            <a-list class="tab-pane"></a-list>
          </a-tab-pane>
          <a-tab-pane tab="待办" key="3">
            <a-list class="tab-pane"></a-list>
          </a-tab-pane>
        </a-tabs> -->
      </a-spin>
    </div>
    <span @click="fetchNotice" class="header-notice">
      <a-badge class="notice-badge" :count="count" :offset="[2,2]">
        <a-icon :class="['header-notice-icon']" type="bell" />
      </a-badge>
    </span>
  </a-dropdown>
    <MessageModal @ok="modalFormOk" ref="modalForm" />
</div>
</template>

<script>
import { Badge as ABadge, List as AList, Avatar as AAvatar, Empty as AEmpty } from 'ant-design-vue'
import { mapGetters } from 'vuex'
import { getAction } from '@/services/manage'
import { filterObj } from '@/utils/util'
import Criteria from '@/utils/criteria'
import { OPERATOR } from '@/store/mutation-types'
import MessageModal from '@/pages/message/modules/MessageModal'
export default {
  name: 'HeaderNotice',
  components: { ABadge, AList, AListItem: AList.Item, AListItemMeta: AList.Item.Meta, AAvatar, AEmpty, MessageModal },
  data() {
    return {
      loading: false,
      show: false,
      count: 0,
      // ws
      maxReconnect: 1, // 最大重连次数,-1代表无限重连
      reconnectTime: 0, // 重连尝试次数
      socket: '',
      uri: '',
      lockReconnect: false,
      timer: null,
      heartbeat: null,
      heartbeatTimeOut: null,
      filters: {},
      dataSource: [],
      url: {
        list: '/message/myUnread/innerMsg'
      },
      heartbeatInterval: 60 * 1000
    }
  },
  computed: {
    ...mapGetters(['token'])
  },
  methods: {
    fetchNotice() {
      if (this.loading) {
        this.loading = false
        return
      }
      this.loadding = true
      setTimeout(() => {
        this.loadding = false
      }, 1000)
    },
    destroyedWs() {
      console.log('ws销毁')
      // 关闭使用close方法关闭socket
      if (this.socket) {
        this.socket.close()
      }
      this.socket = null
      // 清除定时器
      this.timer = null
      clearInterval(this.timer)
      clearTimeout(this.heartbeat)
      this.heartbeat = null
      clearTimeout(this.heartbeatTimeOut)
      this.heartbeatTimeOut = null
    },
    // 初始化方法
    init() {
      this.initWebSocket()
    },
    // 初始化WebSocket
    initWebSocket() {
      if (typeof WebSocket === 'undefined') {
        alert('您的浏览器不支持socket')
      } else {
        var uri = 'ws://' + window.location.host + process.env.VUE_APP_API_BASE_URL + '/ws/message'
        // 实例化socket
        this.socket = new WebSocket(uri, [this.token])
        // 监听socket连接
        this.socket.onopen = this.open
        // 监听socket错误信息
        this.socket.onerror = this.error
        // 监听socket消息
        this.socket.onmessage = this.getMessage
        // 连接关闭
        this.socket.onclose = this.close
      }
    },
    open: function() {
      console.log('socket连接成功')
      this.loadData()
      // 开启心跳
      this.startHeartbeat()
    },
    error: function() {
      console.log('连接错误')
      // 重连
      // this.reconnect()
    },
    getMessage: function(msg) {
      const text = msg.data
      console.log('text', msg)
      // 收到服务器信息，心跳重置并发送
      this.startHeartbeat()
      if (text.indexOf('ping') > 0) {
        return
      }
      this.loadData()
    },
    send: function(params) {
      this.socket.send(params)
    },
    close: function() {
      console.log('socket已经关闭')
    },
    /**
     * 重新连接（无限重连）
     */
    reconnect() {
      if (this.socket.readyState === 1) {
        // 如果状态等于1代表 websocket连接正常
        return
      }
      if (
        this.lockReconnect ||
        (this.maxReconnect !== -1 && this.reconnectTime >= this.maxReconnect)
      ) {
        return
      }

      // 让重连锁变为true，阻止进入下一个循环
      this.lockReconnect = true
      setTimeout(() => {
        this.reconnectTime++
        console.log('尝试重连')
        // 建立新连接
        this.initWebSocket()
        this.lockReconnect = false
      }, 5000)
    },
    /**
     * 开启心跳
     */
    startHeartbeat() {
      const webSocket = this.socket
      // 清空定时器
      clearTimeout(this.heartbeat)
      this.heartbeat = null
      clearTimeout(this.heartbeatTimeOut)
      this.heartbeatTimeOut = null
      // 延时发送下一次心跳
      // console.log("心跳开启");
      this.heartbeat = setTimeout(() => {
        // 如果连接正常
        // console.log("连接状态", webSocket.readyState);
        if (webSocket.readyState === 1) {
          // 这里发送一个心跳，后端收到后，返回一个心跳消息，
          const params = JSON.stringify({
            type: 'ping'
          })
          webSocket.send(params)
          // 心跳发送后，如果服务器超时未响应则断开，如果响应了会被重置心跳定时器
          this.heartbeatTimeOut = setTimeout(() => {
            webSocket.close()
            // 响应超时时间
          }, 10 * 1000)
        } else {
          // 否则重连
          this.reconnect()
        }
        // 心跳间隔时间是30s
      }, this.heartbeatInterval)
    },
    toMyAnnouncement() {
      this.$router.push('/message/messageList')
    },
    async loadData() {
      if (!this.url.list) {
        this.$message.error('请设置url.list属性!')
        return
      }
      const params = this.getQueryParams()// 查询条件
      this.loading = true
      const res = await getAction(this.url.list, params)
      this.loading = false
      this.count = res.result.totalElements
      this.dataSource = res.result.content
    },
    getQueryParams() { // 获取查询条件
      const queryParam = new Criteria()
      queryParam.addCriterions(this.filters, OPERATOR.LIKE)// 过滤参数转换为jpa支持格式
      queryParam.addOrder({ // 增加排序规则,支持组合排序
        fieldName: 'createTime',
        desc: true
      })
      var param = Object.assign({}, { criteria: queryParam.getEncode() })
      param.pageNo = 1
      param.pageSize = 5
      return filterObj(param)
    },
    handleDetail(data) {
      this.$refs.modalForm.show(data, 'innerMsg')
    },
    modalFormOk() {
      this.loadData()
    }
  },
  beforeDestroy() {
    this.destroyedWs()
  },
  mounted() {
    this.init()
  }
}
</script>

<style lang="less">
  .header-notice{
    display: inline-block;
    transition: all 0.3s;
    span {
      vertical-align: initial;
    }
    .notice-badge{
      color: inherit;
      .header-notice-icon{
        font-size: 16px;
        padding: 4px;
      }
    }
  }
  .dropdown-tabs{
    background-color: @base-bg-color;
    box-shadow: 0 2px 8px @shadow-color;
    border-radius: 4px;
    .tab-pane{
      padding: 0 24px 12px;
      min-height: 250px;
    }
  }
</style>
